package com.niceweather.android.logic.network

import com.niceweather.android.logic.network.service.PlaceService
import com.niceweather.android.logic.network.service.WeatherService
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.lang.RuntimeException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

/**
 *
 * Created by callhh on 2020/6/14
 * NiceWeatherNetwork 单例类
 * 统一的网络数据源访问入口，对所有的网络请求的API进行封装
 *
 */
object NiceWeatherNetwork {

    /**
     * 使用 ServiceCreator 创建了一个 PlaceService 接口的动态代理对象
     */
    private val placeService = ServiceCreator.create(PlaceService::class.java)

    private val weatherService = ServiceCreator.create(WeatherService::class.java)

    private suspend fun <T> Call<T>.await(): T {
        return kotlin.coroutines.suspendCoroutine { continuation ->
            enqueue(object : Callback<T> {
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    val body = response.body()
                    if (body != null) {
                        continuation.resume(body)
                    } else {
                        continuation.resumeWithException(RuntimeException("response body is null"))
                    }
                }

                override fun onFailure(call: Call<T>, t: Throwable) {
                    continuation.resumeWithException(t)
                }

            })
        }
    }


    /**
     * 定义一个searchPlaces()函数
     * 调用PlaceService接口中定义的searchPlaces()方法，发起搜索城市数据请求
     * 因借助协程技术来实现 定义了一个await()函数，并将searchPlaces()函数通过 suspend 关键字被声明成挂起函数
     *
     * 使用说明:
     * 当外部调用NiceWeatherNetwork的searchPlaces()函数时，Retrofit就会立即发起网络请求，同时当前的协程也会被阻塞。
     * 直到服务器响应我们的请求之后，await()函数会将解析出来的数据模型对象取出并返回，同时恢复当前协程的执行
     * searchPlaces()函数在得到await()函数的返回值后将该数据再返回到上一层
     *
     */
    suspend fun searchPlaces(query: String) = placeService.searchPlaces(query).await()

    /**
     * 获取实时的天气信息
     */
    suspend fun getRealtimeWeather(lng: String, lat: String) =
        weatherService.getRealTimeWeather(lng, lat).await()

    /**
     * 获取未来的天气信息
     */
    suspend fun getDailyWeather(lng: String, lat: String) =
        weatherService.getDailyWeather(lng, lat).await()


}